﻿// //   Copyright 2007-2011 Comdiv (F. Sadykov) - http://code.google.com/u/fagim.sadykov/
// //   Supported by Media Technology LTD 
// //    
// //   Licensed under the Apache License, Version 2.0 (the "License");
// //   you may not use this file except in compliance with the License.
// //   You may obtain a copy of the License at
// //    
// //        http://www.apache.org/licenses/LICENSE-2.0
// //    
// //   Unless required by applicable law or agreed to in writing, software
// //   distributed under the License is distributed on an "AS IS" BASIS,
// //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// //   See the License for the specific language governing permissions and
// //   limitations under the License.
// //   
// //   MODIFICATIONS HAVE BEEN MADE TO THIS FILE
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace Comdiv.UXmlDiff {
	/// <summary>
	/// generate unique XPath compatible id for any XML element
	/// can use two modes - Safe (no Id attributes used, count selectors only)
	/// </summary>
	public class XDiffIdGenerator {
		public string GenerateId(XObject node, bool safemode = false) {
			if(node.NodeType==XmlNodeType.Document) {
				return "";
			}
			var root = node.Parent == null ? "" : GenerateId(node.Parent,safemode);
			return root + "/" + getSelfSelector(node,safemode);
		}
		string escape(object  id) {
			if (id is string) {
				return ((string)id).Replace("&", "&amp;").Replace("'", "&apos;").Replace("'", "&quot;");
			}
			return ((XAttribute)id).Value.Replace("&", "&amp;").Replace("'", "&apos;").Replace("'", "&quot;");
		}

		private string getSelfSelector(XObject node, bool safemode = false) {
			var result = "";
			if (node.NodeType == XmlNodeType.Element) {
				var e = (XElement) node;
				result += e.Name.LocalName;
				string identity = null;
				if (!safemode) {
					var id = e.Attribute("id");
					var code = e.Attribute("code");
					if (id != null) {
						identity = "@id='" + escape(id) + "'";
					}
					else if (code != null) {
						identity = "@code='" + escape(code) + "'";
					}
				}
				identity = identity ?? (e.NodesBeforeSelf().OfType<XElement>().Where(x => x.Name.LocalName == e.Name.LocalName).Count() + 1).ToString();
				
				result += "[" + identity + "]";
			}
			else if (node.NodeType == XmlNodeType.Attribute) {
				return "@" + ((XAttribute) node).Name.LocalName;
			}
			else if (node.NodeType == XmlNodeType.Text) {
				var identity = (((XText)node).NodesBeforeSelf().OfType<XText>().Count() + 1).ToString();
				return "text()[" + identity + "]";
			}
			else throw new XDiffException("cannot get id for node of type " + node.NodeType);
			return result;
		}
	}
}